package com.fxz.bean.xml;

import com.fxz.bean.definition.BeanDefinition;
import com.fxz.bean.definition.PropertyValue;
import com.fxz.bean.definition.RuntimeBeanReference;
import com.fxz.bean.definition.TypeStringValue;
import com.fxz.bean.factory.registory.BeanDefinitinRegistry;
import com.fxz.bean.utils.ReflectionUtils;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Element;

import java.util.List;

/**
 * 解析Document 并将解析出来的bean进行注册
 *
 * @author Fxz
 * @version 1.0
 * @date 2021-08-12 20:00
 */
public class DefaultBeanDefinitionDocumentReader {

    private BeanDefinitinRegistry beanDefinitinRegistry;

    public DefaultBeanDefinitionDocumentReader(BeanDefinitinRegistry beanDefinitinRegistry) {
        this.beanDefinitinRegistry = beanDefinitinRegistry;
    }


    public void registerBeanDefinitions(Element rootElement) {
        //获取bean标签和自定义标签
        List<Element> elements = rootElement.elements();
        elements.forEach(element -> {
            //获取标签
            String name = element.getName();
            if (name.equals("bean")) {
                //解析默认标签
                parseDefaultElement(element);
            } else {
                //解析自定义的标签
                parseCustomElement(element);
            }
        });
    }

    /**
     * 解析bean标签
     *
     * @param beanElement
     */
    @SneakyThrows
    private void parseDefaultElement(Element beanElement) {

        if (beanElement == null) {
            return;
        }

        String id = beanElement.attributeValue("id");
        String name = beanElement.attributeValue("name");
        //获取Class属性
        String className = beanElement.attributeValue("class");
        if (StringUtils.isBlank(className)) {
            return;
        }
        Class<?> aClass = Class.forName(className);
        String scope = beanElement.attributeValue("scope");
        //如果scope为空 则设置默认值单例
        if (StringUtils.isBlank(scope)) {
            scope = "singleton";
        }
        //获取beanName
        String beanName = StringUtils.isBlank(id) ? name : id;
        if (StringUtils.isBlank(beanName)) {
            beanName = aClass.getSimpleName();
        }
        //创建BeanDefinition
        BeanDefinition beanDefinition = new BeanDefinition(beanName, className);
        beanDefinition.setScope(scope);

        List<Element> propertyElements = beanElement.elements();
        //解析property标签 并将property添加到BeanDefinition
        propertyElements.forEach(propertyElement -> {
            parsePropertyElement(beanDefinition, propertyElement);
        });
        beanDefinitinRegistry.registryBeanDefinitin(beanName, beanDefinition);
    }

    /**
     * 解析property标签 并将property添加到BeanDefinition
     * @param beanDefinition
     * @param propertyElement
     */
    private void parsePropertyElement(BeanDefinition beanDefinition, Element propertyElement) {
        if (beanDefinition == null || propertyElement == null) {
            return;
        }
        //获取name属性
        String name = propertyElement.attributeValue("name");
        //获取value属性
        String value = propertyElement.attributeValue("value");
        //获取ref属性
        String ref = propertyElement.attributeValue("ref");
        //判断是ref还是value
        if (StringUtils.isNotBlank(value) && StringUtils.isNotBlank(ref)) {
            System.err.println("value和ref同时存在!");
            return;
        } else if (StringUtils.isNotBlank(value)) {
            TypeStringValue typeStringValue = new TypeStringValue(value);
            //获取字段类型
            Class<?> targetType = ReflectionUtils.getTypeByFiledName(beanDefinition.getClassName(), name);
            typeStringValue.setTargetType(targetType);
            PropertyValue<TypeStringValue> typeStringValuePropertyValue = new PropertyValue<>(name, typeStringValue);
            beanDefinition.addPropertyValue(typeStringValuePropertyValue);
        } else if (StringUtils.isNotBlank(ref)) {
            RuntimeBeanReference runtimeBeanReference = new RuntimeBeanReference(ref);
            PropertyValue propertyValue = new PropertyValue(name, runtimeBeanReference);
            beanDefinition.addPropertyValue(propertyValue);
        } else {
            System.err.println("value和ref同时为空!");
            return;
        }

    }

    private void parseCustomElement(Element element) {
        //......
    }
}
